package org.xiaoyu.rpc;

import io.netty.channel.Channel;
import lombok.extern.slf4j.Slf4j;
import org.xiaoyu.rpc.common.exception.RpcException;
import org.xiaoyu.rpc.common.extension.ExtensionLoader;
import org.xiaoyu.rpc.common.url.URL;
import org.xiaoyu.rpc.protocol.AbstractProtocol;
import org.xiaoyu.rpc.protocol.Protocol;
import org.xiaoyu.rpc.remoting.packet.Invocation;

import java.lang.ref.WeakReference;

/**
 * Created By Have
 * 2021/7/12 21:24
 */
@Slf4j
public class RpcProtocol extends AbstractProtocol {
    private static final String NAME ="rpc";
    public static final int DEFAULT_PORT = 20888;
    private static RpcProtocol INSTANCE;

    public RpcProtocol() {
        INSTANCE = this;
    }

    public static RpcProtocol getRpcProtocol() {
        if (INSTANCE == null) {
            synchronized (INSTANCE) {
                if (INSTANCE == null) {
                    INSTANCE = (RpcProtocol) ExtensionLoader.getExtensionLoader(Protocol.class).getExtension(NAME);
                }
            }
        }
        return INSTANCE;
    }

    @Override
    public int getDefaultPort() {
        return DEFAULT_PORT;
    }

    @Override
    public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {
        URL url = invoker.getUrl();
        String key = url.getServiceName();
        RpcExporter<T> exporter = new RpcExporter<>(invoker, key, exporterMap);
        invokers.add(new WeakReference<>(invoker));
        exporterMap.put(key, exporter);
        if (log.isInfoEnabled()) {
            log.info("export service:[{}]", invoker.getUrl().getServiceUniqueName());
        }
        return exporter;
    }

    @Override
    public Invoker<?> getInvoker(Channel channel, Invocation invocation) {
        if (invocation == null) {
            throw new IllegalArgumentException("invocation == null");
        }
        URL url = invocation.getUrl();
        String serviceName = url.getServiceName();
        if (log.isInfoEnabled()) {
            log.info("Invoke service Name:[{}]", serviceName);
        }
        Exporter<?> exporter = exporterMap.get(serviceName);
        return exporter.getInvoker();
    }
}
